package com.btcode.web.upload.servlet;

import com.btcode.common.MyLog;
import com.btcode.log.ILog;
import com.btcode.web.core.controller.Controller;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * 附件上传地址格式为：http://{host}:{port}/{contextPath}/{urlPrefix}/dir/dir/dir/……
 * 其中host.port,contextPath,urlPrefix
 *
 * @author gislin
 */
public class FileUploadServlet extends Controller implements Servlet {

    // 禁止上传文件后缀名单
    private String[] extensions = new String[] {"php","php2","php3","php4","php5","phpm","phpml","phtml","phtm","phps",
            "pht","asp","aspx", "asa","cer","cdx","ashx","exe","sh","bash","jsp","jspx","jspa","html","web.config",
            "cfm","cgi","war","ashx","htaccess","py","pl"};

    /***
     * 文件上传白名单
     */
    public static List<String> strs = new ArrayList<>(
            Arrays.asList(".jpg",".jpeg",".png",".gif",".pdf",".doc",".docx",".xls",".xlsx",".7z",".rar",".zip",".pptx",".ppt",".dwg")
    );

    private String uploadBasePath;
    /**
     * 请求前缀，在地址解析的时候，会把地址中的这部分去掉
     */
    private String urlPrefix;

    private String contextPath;

    private ILog log;

    public FileUploadServlet(String uploadBasePath, String urlPrefix) throws URISyntaxException {

        File dir = new File(uploadBasePath);
        this.log = MyLog.getInstance().getLogger(getClass());
        this.uploadBasePath = dir.toURI().toString();
        this.urlPrefix = urlPrefix;
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        contextPath = config.getServletContext().getContextPath();

    }

    @Override
    public ServletConfig getServletConfig() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException {

        try {

            HttpServletRequest request = (HttpServletRequest) req;

            DiskFileItemFactory factory = new DiskFileItemFactory();
            factory.setSizeThreshold(1024 * 1025 * 100);
            File tempDirectory = new File(new URI(uploadBasePath));
            factory.setRepository(tempDirectory);
            ServletFileUpload upload = new ServletFileUpload(factory);
            SimpleDateFormat sfd = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat sfy = new SimpleDateFormat("yyyy");
            Date day=new Date() ;
            //文件保存路径，加上日期文件夹。
            String requestURI = request.getRequestURI() + "/" + sfy.format(day) + "/" + sfd.format(day);
            String basePath = mkdirs(requestURI);
            String finalName = null;
            String uriForServer = getFileURLForServer(requestURI);

            /**
             * 设置上传的文件大小临界值，超出会报错
             */
            upload.setSizeMax(1024 * 1024 * 100);

            List<FileItem> items = upload.parseRequest(request);
            for (FileItem item : items) {
                if (!item.isFormField()) {

                    SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
                    finalName = item.getName();
                    String extension = "";
                    if (finalName.contains(".")) {
                        String fileName = finalName.substring(0, finalName.lastIndexOf("."));
                        extension = finalName.substring(finalName.lastIndexOf("."), finalName.length());
                        // 如果文件后缀名为禁止上传名单则抛出异常
                        for (String s : extensions) {
                            String notUpload = "." + s;
                            if (notUpload.equals(extension.toUpperCase())) {
                                throw new Exception("文件为禁止上传类型");
                            }
                        }
                        String s=extension.toLowerCase();
                        if(!strs.contains(s)) {
                            throw new Exception("文件类型错误");
                        }
                        finalName = fileName + "-" + sf.format(new Date()) + extension;
                    }
                    File file;
                    try {
                        // wangli add 解决带#文件不能上传
                        finalName = finalName.replaceAll(" ", "");
                        finalName = finalName.replaceAll("#", "%23");
                        file = new File(new URI(basePath + "/" + finalName));
                    } catch (URISyntaxException e) {
                        // URL语法错误，说明文件名不支持，采用随机文件名
                        finalName = UUID.randomUUID().toString().substring(0, 4) + "-" + sf.format(new Date()) + extension;
                        file = new File(new URI(basePath + "/" + finalName));
                    }
                    item.write(file);
                    break;
                }
            }

            HashMap<String, String> responeObj = new HashMap<>();
            responeObj.put("url", uriForServer + finalName);
            success(responeObj);
        } catch (Exception e) {
            log.error("上传失败", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据上传请求，创建目录，并把最终的物理URI返回
     */
    private String mkdirs(String requestURL) throws URISyntaxException {
        String url = requestURL.replaceFirst(urlPrefix, "").replaceFirst(contextPath, "");
        String[] dirs = url.split("/");
        String finalDir = uploadBasePath;
        if (finalDir.endsWith("/")) {
            finalDir = finalDir.substring(0, finalDir.length() - 1);
        }

        StringBuffer dirPathBuf = new StringBuffer(finalDir);
        for (String dir : dirs) {
            dirPathBuf.append("/" + dir);
            File file = new File(new URI(dirPathBuf.toString()));
            //根据File里的路径名建立文件夹.
            // （如果父文件夹不存在并且最后一级子文件夹不存在，它就自动新建所有路经里写的文件夹；如果父文件夹存在，它就直接在已经存在的父文件夹下新建子文件夹
            file.mkdirs();
        }
        return dirPathBuf.toString();
    }

    /**
     * 获取文件在服务端的地址
     */
    private String getFileURLForServer(String requestURL) {
        String url = requestURL.replaceFirst(urlPrefix, "").replaceFirst(contextPath, "");
        String[] dirs = url.split("/");

        StringBuffer finalDir = new StringBuffer();

        for (String dir : dirs) {
            finalDir.append(dir + "/");
        }

        return finalDir.toString();
    }

    @Override
    public String getServletInfo() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }

}
